﻿package Banner  {
	import flash.display.*;
	import flash.events.*;
	import flash.net.*;
	import flash.utils.Timer;
    import flash.external.ExternalInterface;  
	import flash.ui.*;
	
	// class to create a movieclip loader into a banner from an external source.
	public class BannerLoader extends Sprite {
		// The extenal source object with set interface. 		
		private var externalSource;
		
		private var loadedClips:Array; 
		private var nClips:Number;
		private var nStageClips:Number;
		private var nLoadedClips:Number;
		private var totalClips:Number;
		public static var spaceWidth:Number  = 2;
		public static var jsFullsize:String = null;
		public static var singleClickFullSize:Boolean = false;
		public static var randomizeStart:Boolean = true;
		
		// width tracking variables.
		private var cWidth:Number;
		private var cHeight:Number;
		private var trackedWidth:Number;
		
		// Scrolling parameters.
		public static var scrollJump:Number  = -1;
		public static var fixedSpeed:Boolean = false;
		public static var simpleTimer:Boolean = false;
		private const scrollRes:Number = 20;		// 100 milisec resolution for scrolling
		private var scrollTimer:Timer;
		private var toScroll:Boolean;
		private const isTimerScroll:Boolean = false; 
		
		// Record current mouse position.
		private var dragDistance:Number;
		private var lastMouseX:Number;
		private var lastMouseX2:Number;
		public static var dragEnabled:Boolean = true;
		
		private var lastMouseXTime:Number;
		private var lastMouseX2Time:Number;
		private var firstClick:Number;
		private var dragStarted:Boolean;
		private var prevTime:Number; 
		
		// The mouse.
		public var mouseCursor:Loader;
		private const cursorURI:String = "bannercursor.png"; 
		
		// Initialize the banner objects.
		public function BannerLoader(stageWidth:Number, stageHeight:Number)
		{
			var cursorReq:URLRequest;
			
			dragDistance = 0;
			lastMouseX = 0;
			nClips = 0;
			nLoadedClips = 0;
			cWidth = stageWidth;
			cHeight = stageHeight;
			firstClick = 0;
			dragStarted = false;
			toScroll = false;

			if(dragEnabled)
			{				
				cursorReq = new URLRequest(cursorURI);
				mouseCursor = new Loader();
				mouseCursor.visible = false;
//				mouseCursor.load(cursorReq);
//				Mouse.hide();
				Mouse.cursor = MouseCursor.BUTTON;
			}
		}
		
		// Add the scroll banner to the stage object passed.
		public function AddToStage(stage)
		{
			stage.addChild(this);
//			stage.addChild(mouseCursor);

			if(dragEnabled)
			{
				stage.addEventListener(Event.MOUSE_LEAVE, HideCursor);
				stage.addEventListener(MouseEvent.MOUSE_DOWN, StartStripDrag);
				stage.addEventListener(MouseEvent.MOUSE_UP, StopStripDrag);
				stage.addEventListener(MouseEvent.MOUSE_MOVE, StripDrag);
				stage.addEventListener(Event.ENTER_FRAME, ScrollImgStripOnFrame);
			}
			
			stage.addEventListener(Event.RESIZE, RescaleBanner);
		}
		
		public function tmp(e:Event)
		{
			trace("event frame entered at time." + new Date().getTime());
		}
		
		
		// Call this function when the external source is ready.
		public function BannerCallback(extSrc)
		{
			externalSource = extSrc;
			this.x = 0;
			this.y = 0;

			// Calculate the number of clips necessary.
			nStageClips = 0;
			var n:Number = 0;
			var clipUri:URLRequest;
			var aspect:Number;
			trackedWidth = 0;
			
			nClips = externalSource.GetGallerySize();
			loadedClips = new Array(nClips + 20);
			
			// Randomize the starting image to show.
			if(randomizeStart)
				externalSource.Random();

			while(externalSource.GetNextFilename())
			{
				aspect = cHeight / externalSource.gFileHeight;
				
				if(trackedWidth <= cWidth)
				{
					trackedWidth += externalSource.gFileWidth * aspect + spaceWidth;
					nStageClips++;
				}
				

				// Create the loader object.
				clipUri = new URLRequest(externalSource.gFileSrc);
				loadedClips[n] = new BannerImg();
				loadedClips[n].contentLoaderInfo.addEventListener(Event.COMPLETE, ScrollBanner);
				loadedClips[n].x = trackedWidth - externalSource.gFileWidth * aspect;
				loadedClips[n].fullsizeURI = externalSource.gFileFullsize;
				if(externalSource.gFileTitle)
					loadedClips[n].imgTitle = externalSource.gFileTitle;
				loadedClips[n].load(clipUri);
				loadedClips[n].scaleX = aspect;
				loadedClips[n].scaleY = aspect;
				addChildAt(loadedClips[n], 0);
				n++;
			}
			
			// Heuristic to handle extreme width changes
			nStageClips *= 2;
		}
		
		// Callback to when all the images have loaded.
		private function ScrollBanner(e:Event)
		{
			var n, totalTracked:Number;
			
			// Proceed only when all clips are loaded.
			nLoadedClips++;
			if(nLoadedClips < nClips)
				return;
						
			// Duplicate the first nStageClips to the end of the array.
			for(n=0; n<nStageClips; n++)
			{
				loadedClips[n+nClips] = new BannerImg();
				loadedClips[n+nClips].loadBytes(loadedClips[n].contentLoaderInfo.bytes);
				loadedClips[n+nClips].fullsizeURI = loadedClips[n].fullsizeURI;
				loadedClips[n+nClips].imgTitle = loadedClips[n].imgTitle;
				loadedClips[n+nClips].scaleX = loadedClips[n].scaleX;
				loadedClips[n+nClips].scaleY = loadedClips[n].scaleY;
			}
			
			totalClips = nStageClips + nClips;
			trackedWidth = 0;
			
			// Add all the clips to the stage.
			for(n=0; n<nClips; n++)
			{
				loadedClips[n].x = trackedWidth;
				trackedWidth += loadedClips[n].width + spaceWidth;
			}
			totalTracked = trackedWidth;
			for(; n<totalClips; n++)
			{
				loadedClips[n].x = totalTracked;
				totalTracked += loadedClips[n-nClips].width + spaceWidth;
				addChildAt(loadedClips[n], 0);
			}
			
			// start scrolling the banner.
//			if(randomizeStart)
//				moveStrip(- Math.random() * totalTracked);
			
			if(isTimerScroll)
			{
				scrollTimer = new Timer(scrollRes);
				scrollTimer.addEventListener(TimerEvent.TIMER, ScrollImgStrip);
				prevTime = (new Date()).getTime();
				scrollTimer.start();
			}
			else
			{
				toScroll = true;
			}
		}
		
		
		// Callback when the stage is resized.
		private function RescaleBanner(e:Event)
		{
			var n, totalTracked:Number;
			var stageAspect, aspect:Number;
			
			stageAspect = e.currentTarget.stageHeight / cHeight;
			cWidth = e.currentTarget.stageWidth;
			cHeight = e.currentTarget.stageHeight;
									
			trackedWidth = 0;

			// Rescale and reposition all the clips.
			for(n=0; n<nClips; n++)
			{
				aspect = stageAspect * loadedClips[n].scaleY;
				loadedClips[n].scaleX = aspect;
				loadedClips[n].scaleY = aspect;

				loadedClips[n].x = trackedWidth;
				trackedWidth += loadedClips[n].width + spaceWidth;
			}
			
			totalTracked = trackedWidth;
			for(; n<totalClips; n++)
			{
				aspect = stageAspect * loadedClips[n].scaleY;
				loadedClips[n].scaleX = aspect;
				loadedClips[n].scaleY = aspect;

				loadedClips[n].x = totalTracked;
				totalTracked += loadedClips[n].width + spaceWidth;
			}

			// Find the center of focus and scroll there.
			moveStrip(this.x * stageAspect - this.x);
		}
		
		
		function ScrollImgStripOnFrame(e:Event)	{
			if(toScroll)
			{
				moveStrip(scrollJump);
			}
		}
		
		// ScrollImgStrip is called every scrollRes milisec to scroll the sprite container.
		function ScrollImgStrip(te:TimerEvent)
		{
			// Check the elapsed time for determining the speed amount.  100ms res for scrolling
			if (simpleTimer)
			{
				moveStrip(scrollJump);
			}
			else
			{
				var curTime = (new Date()).getTime();
				var newJump = scrollJump * (curTime-prevTime) / 100;
				var decJump = Math.round(newJump);
				moveStrip(decJump);
				
				if(scrollJump != 0)
					prevTime += decJump * 100 /scrollJump;
				else
					prevTime = curTime;
			}
			
			te.updateAfterEvent();
		}
		
		// A handler for moving the strip around, handles wraparounds.
		function moveStrip(amnt)
		{
			// Handle rollovers
			if(this.x + amnt < -trackedWidth)
				this.x += trackedWidth + amnt;
			else if(this.x > 0)
				this.x -= trackedWidth;
			else
				this.x += amnt;
		}
		
		// Handle the mouse dragging events for scrolling the image strip.
		function StartStripDrag(me:MouseEvent)
		{				
			dragStarted = true;
			
			if(isTimerScroll)
				scrollTimer.reset();
			else
				toScroll = false;

			dragDistance = 0;
			lastMouseX = me.stageX;
			lastMouseX2 = lastMouseX;
			var dateObj = new Date();
			lastMouseXTime = dateObj.getTime();
			lastMouseX2Time = lastMouseXTime;
		}
		
		function StopStripDrag(me:MouseEvent)
		{
			var dateObj = new Date();
			var curTime:Number = dateObj.getTime();
			
			if(Mouse.cursor == MouseCursor.HAND)
				Mouse.cursor = MouseCursor.BUTTON;

			// Check if there is a double click.
			if(curTime - firstClick < 500 || (singleClickFullSize && 0 == dragDistance))
				ShowFullsize(me);
				
			dragStarted = false;

			firstClick = curTime;
			
			// Determine the speed of the motion - for each 10 pixel motion the speed is -1.
			if(me.stageX == lastMouseX2)
				return;			
			
			if(!fixedSpeed)
			{
				scrollJump = int((me.stageX - lastMouseX2) * 5 / (curTime - lastMouseX2Time));
			}
			else if((me.stageX - lastMouseX2) * scrollJump < 0)
			{
				scrollJump = -scrollJump;
			}

			if(isTimerScroll)
			{
				prevTime = (new Date()).getTime();			
				scrollTimer.start();
			}
			else
			{
				toScroll = true;
			}
		}
		
		function StripDrag(me:MouseEvent)
		{
		 	var sx:Number;
			sx = me.stageX;
			
//			mouseCursor.x = sx;
//			mouseCursor.y = me.stageY;
//			if(!mouseCursor.visible)
//				mouseCursor.visible = true;

			if(me.buttonDown)
			{
				// This is a hack that may be useful for registering mouse down on the touchpad of a notebook.
				if(!dragStarted)
					StartStripDrag(me);
				if(Mouse.cursor == MouseCursor.BUTTON)
					Mouse.cursor = MouseCursor.HAND;

				var dateObj = new Date();
				var curTime:Number = dateObj.getTime();
				dragDistance = (int)(sx - lastMouseX);
				moveStrip(dragDistance);
				lastMouseX2 = lastMouseX;
				lastMouseX = sx;
				lastMouseX2Time = lastMouseXTime;
				lastMouseXTime = curTime;
			}
				
			me.updateAfterEvent();
		}
		
		// When the image is double-clicked call the set javascript callback to display the fullsize image.
		function ShowFullsize(me:MouseEvent)
		{
			if((jsFullsize != null) && (ExternalInterface.available) && (me.target is BannerImg)) 
			{
				// The callback function needs the location of the image to pop an image out of it.
				ExternalInterface.call(jsFullsize, me.target.x + me.target.parent.x, me.target.y, me.target.width, me.target.height, me.target.imgTitle, me.target.fullsizeURI);
			}
		}
		
		function HideCursor(e:Event)
		{
			mouseCursor.visible = false;
		}
	}
}                      


import flash.display.*;

internal class BannerImg extends Loader  {
	public var fullsizeURI:String;
	public var imgTitle:String;
	
	public function BannerImg()
	{
		fullsizeURI = null;
		imgTitle = "Star of the sea";
	}
}
